package com.inoneone.youba.mcht.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.inoneone.toolkit.SnowFlake;
import com.inoneone.toolkit.enums.CardQueryType;
import com.inoneone.toolkit.enums.ChangeType;
import com.inoneone.toolkit.enums.Subject;
import com.inoneone.toolkit.exception.AssertUtil;
import com.inoneone.toolkit.exception.BusinessRuntimeException;
import com.inoneone.toolkit.exception.RegExp;
import com.inoneone.youba.mcht.dao.mapper.CapitalFlowMapper;
import com.inoneone.youba.mcht.dao.mapper.CardMapper;
import com.inoneone.youba.mcht.dao.mapper.ExtendCardMapper;
import com.inoneone.youba.mcht.dao.po.CapitalFlow;
import com.inoneone.youba.mcht.dao.po.CapitalFlowExample;
import com.inoneone.youba.mcht.dao.po.Card;
import com.inoneone.youba.mcht.dao.po.CardExample;
import com.inoneone.youba.mcht.dto.PageRsp;
import com.inoneone.youba.mcht.dto.req.*;
import com.inoneone.youba.mcht.dto.rsp.CardFlowRsp;
import com.inoneone.youba.mcht.dto.rsp.MyCardsRsp;
import com.inoneone.youba.mcht.enums.ErrorCode;
import com.inoneone.youba.mcht.service.CardApi;
import com.inoneone.youba.mcht.util.CommonUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;

@Service
public class CardApiImpl implements CardApi {
    Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    CardMapper cardMapper;

    @Autowired
    CapitalFlowMapper capitalFlowMapper;

    @Autowired
    ExtendCardMapper extendCardMapper;

    @Autowired
    SnowFlake snowFlake;

    @Override
    public Card queryCard(String cardId, String mchId) {
        Card card = cardMapper.selectByPrimaryKey(cardId);
        if (card == null) {
            throw new BusinessRuntimeException(ErrorCode.CARD_NOT_EXIST);

        }
        if (!mchId.equals(card.getMchId())) {
            throw new BusinessRuntimeException(ErrorCode.CARD_MCH_NOT_MATCH);
        }
        return card;
    }

    @Override
    public void checkBatchCards(List<String> cardIds, String mchId) {
        CardExample cardExample = new CardExample();
        cardExample.createCriteria().andCardIdIn(cardIds).andMchIdEqualTo(mchId);
        long cardsCount = cardMapper.countByExample(cardExample);
        if (cardIds.size() != cardsCount) {
            throw new BusinessRuntimeException(ErrorCode.BATCH_CARDS_NOT_EXIST);
        }
    }

    @Override
    public PageRsp<MyCardsRsp> queryCard(MyCardsReq myCardsReq, String mchId) {

        //拼装条件
        CardExample cardExample = new CardExample();
        CardExample.Criteria criteria = cardExample.createCriteria().andMchIdEqualTo(mchId);

        if (!CommonUtil.isNullOrEmpty(myCardsReq.getQueryValue())) {
            if (myCardsReq.getQueryType() == CardQueryType.MOBILE.getCode()) {
                criteria.andMobileLike("%" + myCardsReq.getQueryValue() + "%");
            } else if (myCardsReq.getQueryType() == CardQueryType.REAL_NAME.getCode()) {
                criteria.andUserNameLike("%" + myCardsReq.getQueryValue() + "%");
            } else if (myCardsReq.getQueryType() == CardQueryType.COMPANY.getCode()) {
                criteria.andCompanyLike("%" + myCardsReq.getQueryValue() + "%");
            } else if (myCardsReq.getQueryType() == CardQueryType.CRAD_NO.getCode()) {
                criteria.andCardIdLike("%" + myCardsReq.getQueryValue() + "%");
            } else {
                throw new BusinessRuntimeException(ErrorCode.SYS_ERR);
            }
        }

        //分页查询数据
        PageHelper.startPage(myCardsReq.getPageNum(), myCardsReq.getPageSize());
        List<Card> cards = cardMapper.selectByExample(cardExample);
        PageInfo<Card> pageCards = new PageInfo<>(cards);

        //转换输出类
        List<MyCardsRsp> myCardsRspList = new ArrayList<>();
        for (Card card : cards) {
            MyCardsRsp myCardsRsp = new MyCardsRsp();
            BeanUtils.copyProperties(card, myCardsRsp);
            myCardsRspList.add(myCardsRsp);
        }
        PageRsp<MyCardsRsp> myCardsRspPageRsp = new PageRsp<>(pageCards.getTotal(), pageCards.getPageSize(), pageCards.getPageNum(), myCardsRspList);

        return myCardsRspPageRsp;
    }

    @Override
    public PageRsp<MyCardsRsp> queryCardPlus(String keyWords, String mchId, int pageNum, int pageSize) {

        //拼装条件
        CardExample cardExample = new CardExample();

        if (!CommonUtil.isNullOrEmpty(keyWords)) {
            CardExample.Criteria criteria = cardExample.createCriteria().andMchIdEqualTo(mchId);
            CardExample.Criteria criteria2 = cardExample.createCriteria().andMchIdEqualTo(mchId);
            if(Pattern.matches(RegExp.ZH, keyWords))
            {
                //中文
                criteria.andUserNameLike("%" +keyWords + "%");
                criteria2.andCompanyLike("%" +keyWords + "%");
            }
            else
            {
                criteria.andMobileLike("%" +keyWords + "%");
                criteria2.andCardIdLike("%" +keyWords + "%");
            }
            cardExample.or(criteria2);
        }
        else
        {
            cardExample.createCriteria().andMchIdEqualTo(mchId);
        }


        //分页查询数据
        PageHelper.startPage(pageNum, pageSize);
        List<Card> cards = cardMapper.selectByExample(cardExample);
        PageInfo<Card> pageCards = new PageInfo<>(cards);

        //转换输出类
        List<MyCardsRsp> myCardsRspList = new ArrayList<>();
        for (Card card : cards) {
            MyCardsRsp myCardsRsp = new MyCardsRsp();
            BeanUtils.copyProperties(card, myCardsRsp);
            myCardsRspList.add(myCardsRsp);
        }
        PageRsp<MyCardsRsp> myCardsRspPageRsp = new PageRsp<>(pageCards.getTotal(), pageCards.getPageSize(), pageCards.getPageNum(), myCardsRspList);

        return myCardsRspPageRsp;
    }

    /**
     * Description: 查询流水信息</br>
     * Date: 2017-06-26 16:27:13</br>
     *
     * @param cardFlowReq@return
     * @author 姬远玄
     * @since JDK 1.7
     */
    @Override
    public PageRsp<CardFlowRsp> cardFlow(CardFlowReq cardFlowReq, String mchId) {
        CapitalFlowExample capitalFlowExample = new CapitalFlowExample();
        capitalFlowExample.setOrderByClause("create_time desc");
        CapitalFlowExample.Criteria criteria = capitalFlowExample.createCriteria();
        criteria.andMchIdEqualTo(mchId);
        if (!CommonUtil.isNullOrEmpty(cardFlowReq.getCardId())) {
            criteria.andCardIdEqualTo(cardFlowReq.getCardId());
        }
        if (cardFlowReq.getBeginTime() != null) {
            criteria.andCreateTimeGreaterThanOrEqualTo(new Date(cardFlowReq.getBeginTime()));
        }
        if (cardFlowReq.getEndTime() != null) {
            criteria.andCreateTimeLessThan(new Date(cardFlowReq.getEndTime()));
        }

        //分页查询
        logger.debug("开始分页查询" + cardFlowReq.toString());
        PageHelper.startPage(cardFlowReq.getPageNum(), cardFlowReq.getPageSize());
        List<CapitalFlow> capitalFlows = capitalFlowMapper.selectByExample(capitalFlowExample);
        PageInfo<CapitalFlow> pageCapitalFlow = new PageInfo<>(capitalFlows);

        //转换输出类
        List<CardFlowRsp> cardFlowRspList = new ArrayList<>();
        for (CapitalFlow capitalFlow : capitalFlows) {
            CardFlowRsp cardFlowRsp = new CardFlowRsp();
            BeanUtils.copyProperties(capitalFlow, cardFlowRsp);
            cardFlowRspList.add(cardFlowRsp);
        }
        PageRsp<CardFlowRsp> pageCardFlowRsp = new PageRsp<>(pageCapitalFlow.getTotal(), pageCapitalFlow.getPageSize(), pageCapitalFlow.getPageNum(), cardFlowRspList);

        return pageCardFlowRsp;
    }

    /**
     * Description: ic卡充值操作</br>
     * Date: 2017-06-27 16:00:47</br>
     *
     * @param rechargeReq@return
     * @author 姬远玄
     * @since JDK 1.7
     */
    @Override
    @Transactional
    public BigDecimal recharge(RechargeReq rechargeReq, String mchId) {
        Card card = extendCardMapper.selectByPrimaryKeyForUpdate(rechargeReq.getCardId());
        if (card == null) {
            throw new BusinessRuntimeException(ErrorCode.CARD_NOT_EXIST);
        }
        if (!mchId.equals(card.getMchId())) {
            throw new BusinessRuntimeException(ErrorCode.CARD_MCH_NOT_MATCH);
        }

        //增加余额
        Card cardUpdate = new Card();
        cardUpdate.setBalance(new BigDecimal(rechargeReq.getAmount()));
        cardUpdate.setCardId(rechargeReq.getCardId());
        cardUpdate.setBalanceTime(new Date());
        int result = extendCardMapper.updateBalanceByPrimaryKey(cardUpdate);
        if (result != 1) {
            throw new BusinessRuntimeException(ErrorCode.BALANCE_UPDATE);
        }

        //写流水
        CapitalFlow capitalFlow = new CapitalFlow();
        capitalFlow.setBalance(card.getBalance().add(cardUpdate.getBalance()));
        capitalFlow.setCardId(card.getCardId());
        capitalFlow.setChangeAmount(cardUpdate.getBalance());
        capitalFlow.setChangeType(ChangeType.ADD.getCode());
        capitalFlow.setCompany(card.getCompany());
        capitalFlow.setId(snowFlake.nextId());
        capitalFlow.setMchId(card.getMchId());
        capitalFlow.setMchName(card.getMchName());
        capitalFlow.setMobile(card.getMobile());
        capitalFlow.setUserName(card.getUserName());
        capitalFlow.setSubject(Subject.CHARGE.getCode());
        //余额变动时间和流水时间保持统一
        capitalFlow.setCreateTime(cardUpdate.getBalanceTime());
        capitalFlowMapper.insertSelective(capitalFlow);

        return capitalFlow.getBalance();
    }

    /**
     * Description: 冻结/解冻</br>
     * Date: 2017-06-28 10:27:57</br>
     *
     * @param
     * @return
     * @author 姬远玄
     * @since JDK 1.7
     */
    @Override
    public void freeze(FreezeReq freezeReq, int cardStatus, String mchId) {
        Card card = new Card();
        card.setStatus(cardStatus);

        CardExample cardExample = new CardExample();
        cardExample.createCriteria().andCardIdEqualTo(freezeReq.getCardId())
                .andMchIdEqualTo(mchId);
        int result = cardMapper.updateByExampleSelective(card, cardExample);
        if (result != 1) {
            throw new BusinessRuntimeException(ErrorCode.ERR_UPDATE);
        }
    }


    /**
     * Description: 扣款 </br>
     * Date: 2017-06-28 10:28:10</br>
     *
     * @param
     * @return
     * @author 姬远玄
     * @since JDK 1.7
     */
    @Override
    @Transactional
    public BigDecimal reduce(RechargeReq rechargeReq, String mchId, boolean isPay) {
        //校验ic卡是否存在
        Card card = extendCardMapper.selectByPrimaryKeyForUpdate(rechargeReq.getCardId());
        if (card == null) {
            throw new BusinessRuntimeException(ErrorCode.CARD_NOT_EXIST);
        }
        if (!mchId.equals(card.getMchId())) {
            throw new BusinessRuntimeException(ErrorCode.CARD_MCH_NOT_MATCH);
        }

        //校验ic卡余额是否充足
        BigDecimal reduceAmount = new BigDecimal(rechargeReq.getAmount());
        if (card.getBalance().compareTo(reduceAmount) < 0) {
            throw new BusinessRuntimeException(ErrorCode.BALANCE_LESS);
        }

        //扣余额
        Card cardUpdate = new Card();
        cardUpdate.setBalance(reduceAmount);
        cardUpdate.setCardId(rechargeReq.getCardId());
        cardUpdate.setBalanceTime(new Date());
        int result = 0;
        if(isPay)
        {
            result = extendCardMapper.payBalanceByPrimaryKey(cardUpdate);
        }
        else
        {
            result = extendCardMapper.reduceBalanceByPrimaryKey(cardUpdate);
        }
        if (result != 1) {
            throw new BusinessRuntimeException(ErrorCode.BALANCE_UPDATE);
        }

        //写流水
        CapitalFlow capitalFlow = new CapitalFlow();
        capitalFlow.setBalance(card.getBalance().subtract(reduceAmount));
        capitalFlow.setCardId(card.getCardId());
        capitalFlow.setChangeAmount(reduceAmount);
        capitalFlow.setChangeType(ChangeType.REDUCE.getCode());
        capitalFlow.setCompany(card.getCompany());
        capitalFlow.setId(snowFlake.nextId());
        capitalFlow.setMchId(card.getMchId());
        capitalFlow.setMchName(card.getMchName());
        capitalFlow.setMobile(card.getMobile());
        capitalFlow.setUserName(card.getUserName());
        if(isPay)
        {
            capitalFlow.setSubject(Subject.PAY.getCode());
        }
        else {
            capitalFlow.setSubject(Subject.CHARGE.getCode());
        }

        capitalFlow.setCreateTime(cardUpdate.getBalanceTime());
        capitalFlowMapper.insertSelective(capitalFlow);

        return capitalFlow.getBalance();

    }

    /**
     * Description: 修改ic卡信息</br>
     * Date: 2017-06-28 10:28:18</br>
     *
     * @param
     * @return
     * @author 姬远玄
     * @since JDK 1.7
     */
    @Override
    public void editCard(EditCardReq editCardReq, String mchId) {
        Card card = new Card();
        if (editCardReq.getMobile() != null) {
            card.setMobile(editCardReq.getMobile());

        }
        if (editCardReq.getUserName() != null) {
            card.setUserName(editCardReq.getUserName());

        }

        if (editCardReq.getCompany() != null) {
            card.setCompany(editCardReq.getCompany());

        }

        CardExample cardExample = new CardExample();
        cardExample.createCriteria().andCardIdEqualTo(editCardReq.getCardId())
                .andMchIdEqualTo(mchId);


        int result = cardMapper.updateByExampleSelective(card, cardExample);
        if (result != 1) {
            throw new BusinessRuntimeException(ErrorCode.ERR_UPDATE);
        }
    }

    /**
     * Description: 批量充值</br>
     * Date: 2017-06-28 10:41:29</br>
     *
     * @param
     * @return
     * @author 姬远玄
     * @since JDK 1.7
     */
    @Override
    @Transactional
    public void batchRecharge(BatchRechargeReq batchRechargeReq, String mchId) {

        for(String cardId : batchRechargeReq.getCards())
        {
            RechargeReq rechargeReq = new RechargeReq();
            rechargeReq.setCardId(cardId);
            rechargeReq.setAmount(batchRechargeReq.getAmount());
            recharge(rechargeReq, mchId);
        }
    }

    /**
     * Description: 不同金额批量充值</br>
     * Date: 2017-06-28 11:33:19</br>
     *
     * @param batchRecharge2Req@return
     * @author 姬远玄
     * @since JDK 1.7
     */
    @Override
    @Transactional
    public void batchRecharge2(BatchRecharge2Req batchRecharge2Req, String mchId) {
        for (BatchRecharge2Req.CardsBean cardBean : batchRecharge2Req.getCards()) {
            RechargeReq rechargeReq = new RechargeReq();
            rechargeReq.setCardId(cardBean.getCardId());
            rechargeReq.setAmount(cardBean.getAmount());
            recharge(rechargeReq, mchId);
        }
    }
}
